﻿
{ input: "ABBA"
, grammar: function() {
    Module(function Common(l) {
      l.__Language(function Base(l) { with(l) {
        Func.Rule(l, function LetterA(){ return any("A"); });
      }}).Export();
    }, true);
    Module(function Demo(l) {
      l.__Import('DemoLibrary');
      l.__Language(function Lang(l) { with (l) {
        Func.Rule(l, function Main() { return plus(either(Common.Base.LetterA(), DemoLibrary.Lang.LetterB())) });
        Func.Rule(l, function LetterB() { return any("B"); });
      }}).Export();
    });
    Module(function DemoLibrary(l) {
      l.__Import('Demo');
      l.__Language(function Lang(l) { with (l) {
        Func.Rule(l, function LetterB() { return Demo.Lang.LetterB() });
      }}).Export();
    });
    return Module.Exec(function runit(l) { with (l) {
      l.__Import('Demo');
      return [Demo.Lang.Main(), l];
    }});
  }
, result: "ABBA"}
    
// this test is testing a parse of the input string "ABBA"
{ input: "ABBA"
  // defining a function that will create the grammar the test harness will use to parse.
, grammar: function() {
    // declaring an M module named "Common".
    // the variable reference "l" can be thought of as the "current lexical context,
    //   which includes the language as it ends up at 'runtime'".
    Module(function Common(l) {
      // declaring a language named "Base" inside the Common module
      // "with(l)" is a JavaScript shorthand convenience; it adds "l" to the scope
      //   chain that everything within the with() block will use to resolve its variable symbols.
      l.__Language(function Base(l) { with(l) {
        // declaring a parsing rule named "LetterA".  In M, the distinction between tokens and syntax
        //   exists only as an optimization technique; they don't necessarily need to be distinct. So,
        //   JSMeta has "Rule", which can represent either a token or a syntax rule.  Optionally or 
        //   necessarily occuring interleaves can be detected by using "iseq()" in a production's
        //   sequence to signify that interleave text can, well, interleave.
        // This rule will match the letter A.  any("A") means "the literal text 'A'".  It is named any()
        //   because it can take an arbitrary number of literal JS strings as its arguments, and will try
        //   each of them, providing a highly optimized (compared to a full blown alt[ernation]()) choice
        //   of literal tokens.
        Func.Rule(l, function LetterA(){ return any("A"); });
      // Here, the language Base is marked to be exported from the module Common.
      }}).Export();
    // "true" as the 2nd argument to Module signifies that this module (akin to Language.Base and
    //   Language.Grammar) is to be included in all modules declared/registered following this one.
    }, true);
    // declaring a module named "Demo"
    Module(function Demo(l) {
      // importing the DemoLibrary module into Demo's context (making DemoLibrary's exported members available)
      l.__Import('DemoLibrary');
      // declaring a language Lang inside the "Demo" module
      l.__Language(function Lang(l) { with (l) {
        // declaring a rule "Main" for the "Lang" language
        Func.Rule(l, function Main() {
          // This is equivalent to the M source: 
          //   syntax Main = ( Common.Base.LetterA | DemoLibrary.Lang.LetterB )+;
          // Note that it refers to the "LetterB" rule in the library that was imported.
          return plus(either(Common.Base.LetterA(), DemoLibrary.Lang.LetterB())) });
        // declaring a rule "LetterB" inside Demo.Lang
        Func.Rule(l, function LetterB() { return any("B") });
      // marking "Lang" as exported from module Demo
      }}).Export();
    });
    // declaring a module named "DemoLibrary"
    Module(function DemoLibrary(l) {
      // importing the Demo module into DemoLibrary's context.
      // Note that this is a cyclical (recursive) import.
      l.__Import('Demo');
      // Declare a language "Lang" inside module DemoLibrary.
      l.__Language(function Lang(l) { with (l) {
        // Declare a rule in "Lang" named "LetterB".
        // Note that it refers to the imported library Demo.
        // DemoLibrary.Lang.LetterB now refers to Demo.Lang.LetterB.
        Func.Rule(l, function LetterB() { return Demo.Lang.LetterB() });
      // export language "Lang" from module DemoLibrary
      }}).Export();
    });
    // create a stub namespace/context for the test harness, so it imports
    //   the Demo module and uses Demo.Lang.Main as the "Main" production rule.
    return Module.Exec(function runit(l) { with (l) {
      l.__Import('Demo');
      return [Demo.Lang.Main(), l];
    }});
  }
  // the expected output of the parse.  Default projections for named syntax rules
  //   haven't yet been added, but see the other tests for how to define projections
  //   and binding of variables inside sequences.
, result: "ABBA"}
